package com.seeyon.apps.kk.util;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.logging.Log;

import com.seeyon.ctp.common.SystemEnvironment;
import com.seeyon.ctp.common.log.CtpLogFactory;
import com.seeyon.ctp.util.SeeyonSSLProtocolSocketFactory;
import com.seeyon.ctp.util.Strings;
import com.seeyon.ctp.util.json.JSONUtil;

/**
 * 模拟Http客户端访问网络地址，支持get/post两种方式<br>
 * 
 * get
 * 
 * <pre>
 * HttpClientUtil h = new HttpClientUtil();
 * try {
 * 	h.open(&quot;http://news.sina.com.cn&quot;, &quot;get&quot;);
 * 	int status = h.send();
 * 	h.getResponseBodyAsString(&quot;GBK&quot;);
 * }
 * catch (IOException e) {
 * 	logger.error(e.getLocalizedMessage(),e);;
 * }
 * finally {
 * 	h.close();
 * }
 * 
 * HttpClientUtil h = new HttpClientUtil();
 * try {
 * 	h.open(&quot;http://oa.com/something.do&quot;, &quot;post&quot;);
 * 
 * 	h.addParameter("name", "ta");
 * 	h.addParameter("password", "123456");
 * 
 * 	h.setRequestHeader("Cookie", "Language=zh_CN;UserAgent=PC");
 * 
 * 	int status = h.send();
 * 	h.getResponseBodyAsString(&quot;GBK&quot;);
 * }
 * catch (IOException e) {
 * 	logger.error(e.getLocalizedMessage(),e);;
 * }
 * finally {
 * 	h.close();
 * }
 * </pre>
 * 
 * 
 * @author <a href="mailto:tanmf@seeyon.com">Tanmf</a>
 * @version 1.0 2008-4-17
 */
public class HttpClientUtil {
	private static final Log log = CtpLogFactory.getLog(HttpClientUtil.class);
	
	private HttpClient client = null;
	private HttpMethodBase httpMethod = null;
	
	/**
	 * 默认构造，超时默认设置为15秒，如果你要自己指定，请用 {@link #HttpClientUtil(int)}
	 */
	public HttpClientUtil(){
		this(15 * 1000);
	}
	
	/**
	 * 
	 * @param timeoutInMilliseconds 超时时间，单位毫秒
	 */
	public HttpClientUtil(int timeoutInMilliseconds){
		this(timeoutInMilliseconds, timeoutInMilliseconds);
	}



	/**
	 *
	 * @param connectTimeout 连接超时时间，单位毫秒
	 * @param dataTimeout 等待数据超时时间，单位毫秒
	 */
	public HttpClientUtil(int connectTimeout, int dataTimeout){
		client = new HttpClient();
		client.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8");
		setProxy(client);

		HttpConnectionManagerParams ps = client.getHttpConnectionManager().getParams();

		ps.setSoTimeout(dataTimeout);
		ps.setConnectionTimeout(connectTimeout);
	}
	
	/**
	 * 向指定地址发送一个HTTP请求
	 * 
	 * @param url
	 *            绝对地址，如http://a8.seeyon.com/seeyon/logs/v3x.log
	 * @param method 方式 : get post
	 */
	public void open(String url, String method) {
	    if(url.startsWith("https")){
	        Protocol myhttps = new Protocol("https", new SeeyonSSLProtocolSocketFactory(), 443);   
	        Protocol.registerProtocol("https", myhttps);
	    }else{
	    	log.error("访问外部站点请使用HTTPS！！！");
	    }
		if("get".equalsIgnoreCase(method)){
			httpMethod = new GetMethod(url);
		}
		else if("post".equalsIgnoreCase(method)){
			httpMethod = new PostMethod(url);
		}
		else{
			throw new IllegalArgumentException("Unsupport method : " + method);
		}
	}
	
	/**
	 * 构造HTTP GET请求相关资源
	 * @param url 目标地址
	 */
	public void openGet(String url){
		open(url,"get");
	}
	
	/**
	 * 构造HTTP POST请求相关资源
	 * @param url 目标地址
	 */
	public void openPost(String url){
		open(url,"post");
	}
	
	/**
	 * 在open方法之后、send()之前设置
	 * 
	 * @param name
	 * @param value
	 */
	public void setRequestHeader(String name, String value){
		httpMethod.setRequestHeader(name, value);
	}
	
	public void setRequestBodyJson(Object obj){
		String contentType = "application/json; charset=utf-8";
		RequestEntity requestEntity = null;
		try {
			requestEntity = new StringRequestEntity(JSONUtil.toJSONString(obj),contentType,"utf-8");
		} catch (UnsupportedEncodingException e) {
			log.error(e.getLocalizedMessage(), e);
		}
		((PostMethod)httpMethod).setRequestEntity(requestEntity);
	}
	
	public void setRequestBodyFile(FileInputStream fis){
		String contentType = "application/json; charset=utf-8";
		RequestEntity requestEntity = null;
        try {
            requestEntity = new InputStreamRequestEntity(fis, contentType);
            ((PostMethod)httpMethod).setRequestEntity(requestEntity);
        } catch (Exception e) {
        	log.error(e.getLocalizedMessage(), e);
        }
	}
	
	/**
	 * 添加参数
	 * 
	 * @param name
	 * @param value
	 * @throws IllegalArgumentException
	 */
	public void addParameter(String name, String value) throws IllegalArgumentException{
        if ((name == null) || (value == null)) {
            throw new IllegalArgumentException(
                "Arguments to addParameter(String, String) cannot be null");
        }
            
		if(httpMethod instanceof GetMethod){
			String q = httpMethod.getQueryString();
			if(q == null){
				httpMethod.setQueryString(name + "=" + value);
			}
			else{
				httpMethod.setQueryString(q + "&" + name + "=" + value);
			}
		}
		else if(httpMethod instanceof PostMethod){
			((PostMethod)httpMethod).addParameter(name, String.valueOf(value));
		}
	}
	
	/**
	 * 发送Get请求
	 * 
	 * @return 请求状态 200-正常，404-页面不存在，403-禁止访问，500-服务器错误等等
	 * @throws IOException
	 */
	public int send() throws IOException{
		httpMethod.setRequestHeader("Connection", "close");
		
		return client.executeMethod(httpMethod);
	}
	
	/**
	 * 获取response header
	 * 
	 * @return
	 */
	public Map<String, String> getResponseHeader(){
		Map<String, String> r = new HashMap<String, String>();
		Header[] h = httpMethod.getResponseHeaders();
		for (Header header : h) {
			r.put(header.getName(), header.getValue());
		}
		
		return r;
	}
	
	/**
	 * 获取Cookie
	 * 
	 * @return
	 */
	public Map<String, String> getCookies(){
		Map<String, String> r = new HashMap<String, String>();
        Cookie[] cs = client.getState().getCookies();
        for (Cookie c : cs) {
			r.put(c.getName(), c.getValue());
		}
        
        return r;
	}
	
	/**
	 * Returns the response body of the HTTP method
	 * 
	 * @return
	 * @throws IOException
	 */
	public InputStream getResponseBodyAsStream() throws IOException{
		return httpMethod.getResponseBodyAsStream();
	}
	
	/**
	 * 获取网页内容
	 * 
	 * @param contentCharset
	 * @return
	 * @throws IOException
	 */
	public String getResponseBodyAsString(String contentCharset) throws IOException{
		InputStream instream = httpMethod.getResponseBodyAsStream();
        ByteArrayOutputStream outstream = new ByteArrayOutputStream(4096);
        byte[] buffer = new byte[4096];
        int len;
        while ((len = instream.read(buffer)) > 0) {
            outstream.write(buffer, 0, len);
        }
        outstream.close();
        
        byte[] rawdata = outstream.toByteArray();
        
    	if(contentCharset != null){
    		return new String(rawdata, contentCharset);
    	}
    	else{
    		return new String(rawdata);
    	}
	}
	
	
	/**
	 * 获取JSON响应内容
	 * 
	 * @param cls 反序列化的对象类型
	 * @return 
	 * @throws IOException
	 */
	public <T> T getResponseJsonAsObject(Class<T> cls) throws IOException{
		String responseStr = httpMethod.getResponseBodyAsString();
		return JSONUtil.parseJSONString(responseStr, cls);
	}
	
	
	/**
	 * Releases the connection being used by this HTTP method.<br>
	 * 释放连接，千万不要忘记。
	 */
	public void close(){
		if(httpMethod != null){
			try {
				httpMethod.releaseConnection();
			}
			catch (Exception e) {
				// ignore exception
			}
		}
	}
	
	private static void setProxy(HttpClient client){
		String proxyHost = SystemEnvironment.getHttpProxyHost();
		if(Strings.isNotBlank(proxyHost)){
			int proxyPort = SystemEnvironment.getHttpProxyPort();
			
			if(proxyPort > 0){
				client.getHostConfiguration().setProxy(proxyHost, proxyPort);
			}
		}
	}
	
	/**
	 * 简易快捷的方法，直接获得页面的内容
	 * 
	 * @param url
	 *            需要访问的地址
	 * @return
	 */
	public static String getContent(String url){
		if(Strings.isNotBlank(url)){
			HttpClient client = new HttpClient();
			GetMethod get = new GetMethod(url);
			
			setProxy(client);
			
			get.setRequestHeader("Connection", "close");
			
			try {
				client.executeMethod(get);
				return get.getResponseBodyAsString();
			}
			catch (Exception e) {
				log.error("", e);
			}
			finally{
				get.releaseConnection();
			}
		}
		
		return null;
	}
	
	public static void main(String[] args) throws Exception {
		{
			try {
				HttpClientUtil h = new HttpClientUtil();
				h.open("http://news.baidu.com:81", "get");
				h.send();
				String c = h.getResponseBodyAsString("UTF-8");
				h.close();

				log.info(c);
			}
			catch (Exception e) {
				log.error(e.getLocalizedMessage(), e);
			}
		}
		
		{
			HttpClientUtil h = new HttpClientUtil();
			h.open("http://news.baidu.com", "get");
			h.send();
			String c = h.getResponseBodyAsString("UTF-8");
			h.close();

			log.info(c);
		}
	}

}
